home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c-part2 / 14525 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  4.6 KB

  1. Path: keats.ugrad.cs.ubc.ca!not-for-mail
  2. From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: 2d array of pointers to structures ?
  5. Date: 15 Apr 1996 08:27:16 -0700
  6. Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
  7. Message-ID: <4ktpskINNrmc@keats.ugrad.cs.ubc.ca>
  8. References: <829573448snz@willen.demon.co.uk>
  9. NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
  10.  
  11. In article <829573448snz@willen.demon.co.uk>,
  12. Adrian Parker  <adrian@willen.demon.co.uk> wrote:
  13. >
  14. >I need to keep a 2d array of structures, which I have to do at runtime 
  15. >as they array could be quite big, and the compiler can't cope with 
  16. >static arrays of the required size.
  17. >
  18. >Say I have a structure of..
  19. >
  20. >    typedef struct {
  21. >        int id;
  22. >        long colour;
  23. >    } T_loc;
  24. >    T_loc *locptr;
  25. >
  26. >And two variables containing the number of rows and colums.   How do I
  27. >allocate the storage for the memory array, and how then do I reference
  28. >it ?
  29.  
  30. This is up to your fancy, and should probably be determined by the sort of ways
  31. in which you will want to operate on the structure. If you choose a
  32. representation that's easy to implement, it may not easily support operations
  33. whose requirement was not initially forseen.
  34.  
  35. >I know I need to allocate a pointer for each row, so..
  36. >
  37. >    locptr = (T_loc *)malloc(rows);
  38. >
  39. >should allocate enough space to hold "rows" number of T_loc pointers.  
  40.  
  41. No. No cast is necessary, and the argument should be (rows * sizeof(T_loc *))
  42.  
  43. The type of locptr should be:
  44.  
  45.  
  46.     T_loc    **locptr;
  47.  
  48. Because you want it to be a pointer to the first element of an array of
  49. pointers, or a pointer to a pointer.
  50.  
  51. >Then in each entry, I need to store a pointer to an array of columns..
  52. >which is where I'm stuck.. 
  53. >
  54. >    for (x = 0 ; x < rows ; x++)
  55. >    {
  56. >        *(locptr+x) = (T_loc)malloc(cols);
  57.  
  58. You may wish to use an equivalent array notation here:  locptr[x]. But that is
  59. personal preference.
  60.  
  61. >    }
  62.  
  63. The reason it doesn't work is twofold.
  64.  
  65. Firstly, you are incorrectly casting the (void *) return type from malloc() to
  66. a (T_loc). The latter is not a pointer type, but a structure type. You want to
  67. cast to a (T_loc *).
  68.  
  69. However: In ANSI C, you don't have to (and shouldn't) cast a (void *) type.
  70. Just do the assignment! The cast can hide a potential error:
  71.  
  72.     Suppose you forget to include the <stdlib.h> error, and your compiler
  73.     hence doesn't have a prototype for malloc. It will assume that
  74.     the return value is int. By putting a cast there, you occlude the
  75.     possibility that a warning message will catch the error.
  76.  
  77.  
  78. Secondly, you are not giving the appropriate allocation size. If you want to
  79. allocate a number of structures equal to cols, the number of bytes you need is
  80. equivalent to cols * number of bytes in a T_loc.
  81.  
  82. The correct statement is, therefore:
  83.  
  84.  
  85.     *(locptr + x) = malloc(cols * sizeof(T_loc));    /* That's it!    */
  86.  
  87. >which I think should  malloc "cols" number of T_loc variables, and store
  88. >the returned pointer in the 'x'th locptr pointer array..  but obviously
  89. >something is wrong as it won't compile.
  90.  
  91. The above correction should take care of that.
  92.  
  93. >I then need to be able to refer to a specific struct items for a
  94. >specific column in a specific row..
  95. >
  96. >    (T_loc *)((*(locptr+ROW))+COL)->id
  97. >
  98. >or am I way off here too ?
  99.  
  100. Sort of. First of all, no cast is needed to do this, because everything has the
  101. right type. Secondly, in the above expression,  the -> operator has a higher
  102. precedence than the ( ) cast. So what you are doing is casting the id element
  103. to a (T_loc *), which is probably not what you want.
  104.  
  105. You have an extra set of braces around the  *(locptr+ROW) which are not needed,
  106. since * has a much higher precedence over the subsequent + COL.
  107.  
  108. A table of operator precedences appears in K&R2, page 53.
  109.  
  110. The correct expression is:
  111.  
  112.     (  *(locptr + ROW) + COL)) -> id
  113.  
  114. Which is the same as
  115.  
  116.     ( *(*(locptr + ROW) + COL) ) . id 
  117.  
  118. Which is the same as
  119.  
  120.     ( *( locptr[ROW] + COL) ) . id
  121.  
  122. which is just
  123.  
  124.     ( locptr[ROW][COL] ) . id
  125.  
  126. Which is
  127.  
  128.     locptr[ROW][COL].id    /* [] has same prededence level as .    */
  129.                 /* in left to right associativity    */
  130.  
  131. Surprise! Thanks to C's treatment of arrays and pointers, it's the same
  132. expression that you would have used had you been able to declare a full
  133. two-dimensional array!
  134.  
  135. A person reading your source cannot infer the type of ``locptr'' just by
  136. looking at the usage. According to the expression in which it is used, it could
  137. be any one of _four_ possibilities: a two-dimensional array of structures, a
  138. pointer to the first of an array of one-dimensional arrays of structures, a
  139. pointer to the first element of an array of pointers to allocated blocks of
  140. structures (your case), or an array of pointers to allocated structures. 
  141. -- 
  142. I'm not really a jerk, but I play one on Usenet.
  143.